10. ユーザインタフェースのプログラミング
技育祭
https://gyazo.com/b7fc7d89a20e84310efa4ac1c37b75f4
HelpLine
https://s3-ap-northeast-1.amazonaws.com/masui.org/d/b/db555e8535ff111e794b95e6d3d7a8f5.mp4
ソフトウェアのうちユーザインタフェース部分
比率が高い
全プログラムの50%? 80%?
重要な意味をもつ
インタフェース作成の面倒さ
リアルタイム性
様々な要素技術
機能の交錯
並列性
例外処理
インタフェース作成の面倒さ (続き)
柔軟性 / 頑強性
ユーザ補助機能
評価/再設計の繰り返し
インタフェース作成の面倒さ (続き)
様々なプログラミング技法が必要!
リアルタイム性
効率的実装が必要
素早い反応
高速描画
様々な要素技術
グラフィック描画
音声認識
画像認識
入力処理
センサ処理
アプリケーション部とインタフェース部の交錯
計算部とインタフェース部が混合しやすい
再利用が困難
code:sample.c
printf("Input your name: "); # UI part
scanf("%s", name); # UI part
s = calc(name); # Application part
printf("%s\n",s); # UI part
App本体とI/Fの分離
インタフェースが再利用可能になる
異なるインタフェースを利用できる
GUI / CUI
素人用 / 玄人用
カスタマイズ
テスト/デモモジュールを接続可能
分離の困難さ
逐次実行文の字面を分離するのは困難
疎結合にすることは本質的にむずかしい
UI部にはAP部の情報が必要
AP部にはUI部の情報が必要
e.g. メニューの中の不要項目を消したい
← メニューがアプリケーションの状態を知る必要あり
並列処理
システムとユーザは並列に動作
計算中も常に入力受付が必要
様々な対話形態
計算機の質問にユーザが答える (e.g. 「Wizard」)
ユーザが主体で指示を出す
上記の融合
並列処理 (続き)
複数の入力装置を同時に利用
複数のウィンドウ
入力を受けつけながらアニメーションが動く
タイムアウト
例外処理
時間切れ
強制終了
非同期イベント
エラー
ネットワークトラブル
エラー処理記述の面倒さ
記述が面倒
本質(calc)の記述がエラー処理に埋没
code:error.c
if(condition1) ....
if(condition2) ....
result = calc()
if(exception) ...
if(wrongresult) ...
柔軟性/頑強性
操作の間違いへの対応
何をやっても問題無いようにする
間違えにくいデザイン
GUIデザイン
状態遷移の工夫
テスト重要
ユーザ補助機能
ヘルプ
undo
ガイダンス
マニュアル
ユーザ適応
操作予測
評価/再設計の繰り返し
試行錯誤が必須
一度作れば終りではない
評価に時間と労力がかかる
簡易インタプリタ言語が有効
ラピッドプロトタイピング
関連技術
オブジェクト指向プログラミング
プログラムのモジュール化
部品の再利用(e.g. ウィンドウ、メニュー)
MVC model, etc.
https://gyazo.com/ff0753e54a7445e40554e3d21a224b40
関連技術 (続き)
簡易インタプリタ言語
JavaScript, Ruby, Python, ...
試行錯誤のサイクルを高速にするのに有効
関連技術 (続き)
ビジュアルプログラミング
画面設計や状態遷移プログラミング
インタフェースビルダ
並列プログラミング
同時に発生する動作の処理に有効
イベントベース
スレッドベース
関連技術 (続き)
開発環境
プログラム編集、デバッグ、保守、マニュアル作成、etc.
文芸的プログラミング
インタフェース専用システム
制約解決システム
例示プログラミングシステム
適応/学習システム
解決法1: UIMS
UIMS = User Interface Management System
DBMS(Database Management System)からの発想
アプリケーションとインタフェースの分離を支援
複雑な部分は全てUIMS中にもつ
https://gyazo.com/dde7db959c2dac1cda7e3fe677ae39c1
Seeheimモデル
UIMSの有名な(古い)モデル
インタフェースとアプリケーションを抽象化して分離
https://gyazo.com/b39e0ac296c425e1d03c7d7b332655ec
凝ったインタフェースには適用不可能
意味フィードバック(アプリケーション内の情報がインタフェースに直接反映される)が実現できない
UIMSの問題点
あらゆるインタフェースパターンを用意するのは不可能
対話に制限がついてしまう
システムが巨大になりがち
完全な分離支援は不可能
アプリケーションに依存したインタフェースもある
→ 近年あまり流行らない
解決法2: UI記述言語
インタフェースを専用言語で記述
UIMSは専用のUI記述言語を持っていることが多い
c.f. DBMSのSQL
インタフェース言語の例
HyperCard
Squeak: CSPライクな並列言語でUIを記述
ERL: Sassafras UIMSのイベント言語
インタフェース用の言語に関する考察
http://gyazo.com/f10ec195e6a4ac8d2ada4f99a5564dc7.png
UI記述言語の問題点
特殊な専用言語を覚える必要がある
UI記述言語とアプリケーション言語の整合性
c.f. CとSQL
仕様が巨大化
汎用機能と特殊機能が両方必要なため
UI言語に必要なUI機能を絞り込むことはできない
新しい機能を導入しにくい
機能を限定すればうまくいくこともある
解決法3: ツールキット
インタフェース部品をライブラリ化
イベント駆動 (マウス、タイマ、etc.)
制御の主体はツールキット側
イベント発生により「コールバック関数」が呼び出される
GUIアプリケーションで広く利用されている
各種のグラフィックツールキット
Cocoa (Mac)
MFC (Windows)
Flex, Air (Flash)
Swing (Java)
Qt
Tcl/Tk
JavaScriptの各種ライブラリ
オブジェクト指向ツールキット
独立したインタフェース部品
ウィンドウ, テキスト枠, etc.
個有のデータや手続きを持つ
例: NeXTStationのアプリ
https://gyazo.com/79aa0b2cd44cddac73493d410b543177
NeXTstepのプログラム
code:next.c
main(){
...
UIツールキットの問題点
インタラクション手法が決まってしまう
統一感はとりやすい
アプリケーション構築手法が決まってしまう
コールバック関数として実現
制御の自由がない
UIツールキットの問題点 (続き)
必要なライブラリの数が多い
覚えるのが大変!
拡張が不可能であるか難しい
システムや言語が制限される
実用的にはこれが最善
これしか無いと思ってる人も多いかも?
解決策4: 状態遷移プログラミング
プログラム実行状態の変化を記述
UIの状態遷移記述を楽にする
例: ローマ字かな変換の状態遷移
https://i.gyazo.com/caaf304022fdd558037e55e20bb83b4a.png
状態遷移機械の問題点
インタフェースが複雑になると状態の数が非常に多くなる
ひとつの画面上で表現しきれない
状態遷移記述だけではプログラミングが楽にならない
拡張状態遷移機械単純な状態遷移機械を拡張したモデル
階層的状態遷移機械
https://gyazo.com/ab100d3b4b6c35325ae39c5b53b3933e
StateChart
https://gyazo.com/3ccc6469567662626df4ef12327edc9a
並列性を記述できる
複数の状態のモジュール化
状態遷移プログラミング
特殊ツールの利用
プログラミングテクニックによるもの
e.g. StateChartの実装
http://gyazo.com/e9a9a3673399c33937c1ebd8e3b68f8f.png
状態遷移プログラミング例
状態遷移記述言語の利用
code:kana.lex
ka { printf("か"); }
ki { printf("き"); }
kya { printf("きゃ"); }
変換後のソース
code:kana.c
c = getc();
if(c == 'k'){
c = getc();
switch(c){
case 'a': printf("か"); break;
case 'i': printf("き"); break;
case 'y':
c = getc();
if(c == 'a') ...
解決策5: 並列プログラミング
並列処理はUIプログラミングに非常に重要
複数の入出力装置を使う
マウス、キーボード、etc.
複数の入出力を同時に行なう
e.g. ハンドルを回しながらアクセルを踏む
モジュール分割
アプリケーション部とインタフェース部を並列に動かす
複数ユーザ対応
ツールキットの並列動作
あらゆるイベントを一本化
イベントを順番に処理
Event model (toolkit with callbacks)
Thread model (use multiple processes)
並列プログラミングの問題点
特殊な言語やライブラリが必要
アプリケーション言語との整合性
デバッグが大変
並列プログラミングはポピュラーでない
JavaScriptのコールバック
時間がかかる処理はバックグラウンドで動かす
処理が終了するとコールバック関数が呼ばれる
(時間がかかる)処理を順番に実行させるのが難しい
実は並列動作のための枠組み
Promise
コールバックのネストを解決
解決法6: インターフェースビルダ
NeXTで導入
Mac/iPhoneでも利用されている
インターフェースビルダ
ツールキットを対話的に画面配置
アプリケーションプログラム(の骨格)の自動生成
コンパイルせずに操作を実験
ツールキットとの統合 (e.g. Xcode + IB)
NeXTのインタフェースビルダ
http://gyazo.com/26628fafb9d8cddd83ada076705b68fe.png
Xcodeのインタフェースビルダ
http://gyazo.com/fc72e526450de45e308ef0e211a8525b.png
インターフェースビルダの問題点
システムやツールキットに依存する
Mac専用など
対話方式が制限される
GUIにしか使えない
システムが複雑
GUI開発においては現状では最善
解決法7: 制約プログラミング
オブジェクト間の制約を宣言的に記述
システムが制約を自動解決
適用分野
グラフィック図形間の制約
「AはBとCの中間」
どれかを動かすと残りも追随
スプレッドシート
制約が破られると自動的に再計算が行なわれる
いわゆるスプレッドシート以外のアプリケーションにも適用可能
https://www.youtube.com/watch?v=9bEFCPwMWyE
Sketchpad by Ivan Sutherland
https://www.youtube.com/watch?v=3wrn9cxlgls
1963の開発!
制約システムの問題点
適用範囲が狭い
グラフィック配置のみ
制約が複雑なとき解くのに時間がかかる
対話的に使えない場合がある
簡単な制約しか解くことができない
解決法8: 例示プログラミング
操作の例をシステムに与える
システムが具体的な例を一般化
プログラムを自動生成
PBE (Programming by Example)
No code required?
https://www.amazon.co.jp/dp/012381541X https://gyazo.com/37f22e4c6d980cd1caa00617e9fee636
子供用のプログラミング
Graphical Rewrite Rule
http://gyazo.com/66a451fefd3be1832a7418b017065fd9.png
http://www.youtube.com/watch?v=0N8cpLHZ41I
https://www.youtube.com/watch?v=kxeaeCajuFc
https://www.youtube.com/watch?v=L0Gg76f60ao
https://www.youtube.com/watch?v=8q-Pbg8sCV0
例示システムの問題点
単純なプログラミングにしか使えない
例が沢山必要
システムが予想可能な動きに限られる
どうするのがよいか?
ひとつの完璧なシステムは無い
場合によってシステムを選択
工夫のいろいろ
オブジェクト指向ツールキット
並列処理
状態遷移記述の工夫
軽量言語でプロトタイピング
分野に応じたツール (制約システム、etc.)
From scratch, 小規模システムの場合
便利そうな小ツールを捜す
スタンドアロンのコンパクトなツールを使う
Processing
From scratch, 大規模システムの場合
大規模で有用なシステムの使用を検討する
ツールキットを活用する
状態遷移記述の利用
何らかの並行処理を使う
並列言語
コルーチン
Promise
ウィンドウシステムの場合
インタフェースビルダのあるツールキット/IDEを使う
Xcode (Mac)
Visual C++ (Windows)
Visual Studio (Windows)
Android Studio (Android)
VSCode
使いやすいツールキットを選択する
高度なグラフィックシステムを選択する
プロトタイプシステムをとりあえず動かす場合
ブラウザを利用
JavaScript + HTML
Electronでアプリ化する
簡易プログラミングシステムを利用
Processing / Processing.js
インタプリタ + ツールキット
RubyMotion (Ruby + Cocoa)
CLX (X11 + CommonLisp)
Tcl/Tk (Tcl + Tk)
Qt
ツールの実例1: Flex
Flex = 状態遷移コンパイラ
状態遷移を正規表現で記述したものをコンパクトな遷移表に変換
効率の良いCコードを生成
code:roma.flex
%%
ka { printf("か"); }
ki { printf("き"); }
kya { printf("きゃ"); }
→ 状態遷移関数zztrans(入力文字, 遷移機械番号)と遷移表を生成
Flex適用例
code:romakana.flex
%%
a { printf("あ"); }
ba { printf("ば"); }
be { printf("べ"); }
bi { printf("び"); }
bo { printf("ぼ"); }
bu { printf("ぶ"); }
bya { printf("びゃ"); }
bye { printf("びぇ"); }
byi { printf("びぃ"); }
...
zye { printf("じぇ"); }
zyo { printf("じょ");}
zyu { printf("じゅ");}
C 出力
code:flex.c
static short zznstate[] = {
25, 92, 2, 31, 4, 90, 13, 7, 15, 87, 11, 5, 6, 8, 81, 10,
1, 3, 18, 75, 29, 9, 22, 23, 82, 69, 99,175, 83, 65,100,174,
84, 59,101,176,177, 85, 52,102, 88, 0, 86, 63, 89, 17, 28, 12,
...
125, 0,113,151,126, 0, 0,116,152,127, 0, 0,117,153,128, 16,
134,139,119, 0,135,140,120, 0,136,141,121, 0, 0,137,142,122,
0, 0,138,143,123 } ;
zztrans(c,n) int c; int n;
{
int *state;
int index;
state = &(zzstmsn.zzstate); else{
...
}
ツールの実例2: Linda
Linda = 並列言語プリミティブ
共有空間を使った同期/非同期通信
ライブラリの形で既存言語に融合可能
モジュールの分離が可能
https://gyazo.com/db5a5056dcc018768aa8c07eb5bea782
Lindaモデル
タプル(データ組)をタプル空間(共有空間)でやりとりする
4種類のプリミティブ
out Write a tuple in a tuple space
in Read a tuple from the tuple space and delete it
rd Read a tuple from the tuple space, but keep it
https://gyazo.com/7a6db09a858a7c68c2d0a3688476e507
8-Queen
https://gyazo.com/2255edcc7805b037208d333976deac3d
再帰の底でprintqueens()が呼ばれている
「Queenをひとつ計算して印刷する関数」を作りにくい
マウスクリックの度に解を表示するインタフェースを作りにくい
Lindaによる解法
https://gyazo.com/fd294eee60be910eaa2bfe1d354c6013
端末インタフェースをもつ8-Queenプログラム
https://gyazo.com/11b8a7d34650480499f3dc4149e83603
ウィンドウインタフェースをもつ8-Queenプログラム
https://gyazo.com/74da2119decfc775337d22eaf9b8a67c
Node-Linda
Webサーバ上のLinda実装
Running on Masui Lab.
https://www.slideshare.net/shokai/prosym-node-linda https://gyazo.com/716da53b338a9c47e40bf79176fb78a2